package com.zui.base;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.displaytag.properties.SortOrderEnum;
import org.hibernate.Criteria;
import org.hibernate.Query;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Example;
import org.hibernate.criterion.MatchMode;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;

import com.zui.util.JQGridListImpl;
import com.zui.util.Page;
import com.zui.util.PaginatedListImpl;

/**
 * sessionDao接口的Hibernate实现，没有实体类，没有状态
 * 
 * @author
 * @date 2011-9-21
 * @param <T> 实体类
 * @param <ID>
 */
@SuppressWarnings("unchecked")
public class SessionHibernateDao<T, ID extends Serializable> extends
		HibernateDaoSupport implements SessionDao<T, ID> {

	public SessionHibernateDao() {
	}
	@Override
	public T findById(Class<T> c, ID id) {
		T entity;
		entity = (T) getHibernateTemplate().get(c, id);
		return entity;
	}
	@Override
	public T loadById(Class<T> c, ID id) {
		T entity = (T) getHibernateTemplate().load(c, id);
		return entity;
	}
	@Override
	public List<T> loadAll(Class<T> c) {
		return super.getSession().createQuery(
				"from " + c.getName()).list();
	}
	@Override
	public T saveEntity(T entity) {
		getHibernateTemplate().save(entity);
		this.flush();
		return entity;
	}
	@Override
	public void updateEntity(T entity) {
		getHibernateTemplate().saveOrUpdate(entity);
		this.flush();
	}
	@Override
	public void saveOrUpdateAll(Collection<T> entities) {
		int rows = 0;
		for (T t : entities) {
			this.saveEntity(t);
			rows++;
			if (rows % 20 == 0) {
				this.flush(); // 20, same as the JDBC batch size
				this.clear(); // flush a batch of inserts and release memory:
			}
		}
	}
	@Override
	public void deleteEntity(T entity) {
		getHibernateTemplate().delete(entity);
		this.flush();
	}
	@Override
	public void deleteEntityById(Class<T> c, ID id) {
		this.deleteEntity(this.loadById(c, id));
		this.flush();
	}
	@Override
	public void deleteAll(Collection<T> entities) {
		this.flush();
		getHibernateTemplate().deleteAll(entities);
	}
	@Override
	public void merge(T entity) {
		getHibernateTemplate().merge(entity);
		this.flush();
	}
	@Override
	public T getEntity(String hsql) {
		T uniqueResult = (T) super.getSession().createQuery(hsql)
				.uniqueResult();
		return uniqueResult;
	}
	@Override
	public List<T> getEntities(String hsql) {
		return super.getSession().createQuery(hsql).list();

	}
	@Override
	public List<T> getEntities(String hql, int start, int number,
			Object[] values) {
		Query query = super.getSession().createQuery(hql);
		for (int i = 0; i < values.length; i++) {
			query.setParameter(i, values[i]);
		}
		query.setFirstResult(start);
		query.setMaxResults(number);
		List list = query.list();
		return list;
	}
	@Override
	public List<T> getEntities(String hql, int start, int number) {
		Query query = super.getSession().createQuery(hql);
		query.setFirstResult(start);
		query.setMaxResults(number);
		List list = query.list();
		return list;
	}
	@Override
	public List<T> getEntities(String hql, Object[] values) {
		Query query = super.getSession().createQuery(hql);
		for (int i = 0; i < values.length; i++) {
			query.setParameter(i, values[i]);
		}
		return query.list();
	}
	@Override
	public int updateByNamedQuery(String queryName, Object[] values) {
		Query query = super.getSession().getNamedQuery(queryName);
		for (int i = 0; i < values.length; i++) {
			query.setParameter(i, values[i]);
		}
		return query.executeUpdate();
	}
	@Override
	public List<T> findByNamedQuery(String queryName) {
		return super.getSession().getNamedQuery(queryName).list();
	}
	@Override
	public List<T> findByNamedQuery(String queryName, Object[] values) {
		Query query = super.getSession().getNamedQuery(queryName);
		if (values == null)
			return query.list();
		for (int i = 0; i < values.length; i++) {
			query.setParameter(i, values[i]);
		}
		return query.list();
	}
	@Override
	public List<T> findByNamedQuery(String queryName, String[] paramNames,
			Object[] values) {
		Query query = super.getSession().getNamedQuery(queryName);
		for (int i = 0; i < paramNames.length; i++) {
			query.setParameter(paramNames[i], values[i]);
		}
		return query.list();
	}
	@Override
	public Iterator<T> iterate(String hql) {
		return super.getSession().createQuery(hql).iterate();
	}
	@Override
	public Iterator<T> iterate(String hql, Object[] values) {
		Query query = super.getSession().createQuery(hql);
		for (int i = 0; i < values.length; i++) {
			query.setParameter(i, values[i]);
		}
		return query.iterate();
	}
	@Override
	public DetachedCriteria createDetachedCriteria(Class<T> c) {
		return DetachedCriteria.forClass(c);
	}
	@Override
	public Criteria createCriteria(Class<T> c) {
		return this.createDetachedCriteria(c).getExecutableCriteria(
				super.getSession());
	}
	@Override
	public List<T> findByCriteria(DetachedCriteria criteria, int firstResult,
			int maxResults) {
		return criteria.getExecutableCriteria(this.getSession())
				.setFirstResult(firstResult).setMaxResults(maxResults).list();
	}

	/**
	 * 动态查询
	 * 
	 * @param criterion
	 * @return
	 */
	@Override
	public List<T> findByCriteria(Class<T> c, Criterion... criterion) {
		Criteria criteria = getSession().createCriteria(c);
		for (Criterion cri : criterion) {
			if (c != null) {
				criteria.add(cri);
			}
		}
		List list = criteria.list();
		return list;
	}
	@Override
	public Integer getRowCount(DetachedCriteria criteria) {
		criteria.setProjection(Projections.rowCount());
		List list = this.findByCriteria(criteria, 0, 1);
		return (Integer) list.get(0);

	}
	@Override
	public Object getStatValue(DetachedCriteria criteria, String propertyName,
			String StatName) {
		if (StatName.toLowerCase().equals("max"))
			criteria.setProjection(Projections.max(propertyName));
		else if (StatName.toLowerCase().equals("min"))
			criteria.setProjection(Projections.min(propertyName));
		else if (StatName.toLowerCase().equals("avg"))
			criteria.setProjection(Projections.avg(propertyName));
		else if (StatName.toLowerCase().equals("sum"))
			criteria.setProjection(Projections.sum(propertyName));
		else
			return null;
		List list = this.findByCriteria(criteria, 0, 1);
		return list.get(0);
	}
	@Override
	public List<T> findByExample(T exampleInstance) {
		if (exampleInstance == null) return null;
		Criteria crit = getSession().createCriteria(exampleInstance.getClass());
		Example example = Example.create(exampleInstance);
		example.ignoreCase().enableLike(MatchMode.ANYWHERE);// 忽略大小写，并进行模糊比较
		example.excludeZeroes();
		crit.add(example);
		return crit.list();
	}
	@Override
	public void flush() {
		getHibernateTemplate().flush();
	}
	public void clear() {
		getHibernateTemplate().clear();
	}
	public void evict(T entity) {
		getHibernateTemplate().evict(entity);
	}

	/**
	 * 根据criteria和orderList进行分页查询。
	 * 
	 * 出于性能考虑排序信息请勿放在criteria里，由本方法负责。
	 * 
	 * @param criteria
	 *            查询条件
	 * @param page
	 *            分页信息
	 * @param orderList
	 *            定制化的排序列表
	 * @return 包含分页信息的对象列表。对象为根对象。
	 */
	@Override
	public List findByCriteria(DetachedCriteria criteria, Page page,
			List<Order> orderList) {
		if (page == null)
			throw new IllegalArgumentException(
					"page object can not be null value!");
		PaginatedListImpl plh = new PaginatedListImpl();
		plh.setPageNumber(page.getRequestPage());
		plh.setObjectsPerPage(page.getPageSize());

		// get total record num
		criteria.setProjection(Projections.rowCount());
		List count = getHibernateTemplate().findByCriteria(criteria);
		int totalCount = ((Integer) count.get(0)).intValue();
		plh.setfullListSize(totalCount);
		criteria.setProjection(null);

		// default order criteria
		if (page.getSortColumn() != null && page.getSortDirection() != null
				&& !"".equals(page.getSortColumn())
				&& !"".equals(page.getSortDirection())) {
			if (page.getSortDirection().equalsIgnoreCase(
					Page.SORT_DIRECTION_ASCENDING)) {
				criteria.addOrder(Order.asc(page.getSortColumn()));
				plh.setSortDirection(SortOrderEnum.ASCENDING);
			} else {
				criteria.addOrder(Order.desc(page.getSortColumn()));
				plh.setSortDirection(SortOrderEnum.DESCENDING);
			}
			plh.setSortCriterion(page.getSortColumn());
		}

		// custom order
		if (orderList != null) {
			for (Iterator<Order> it = orderList.iterator(); it.hasNext();) {
				criteria.addOrder(it.next());
			}
		}

		criteria.setResultTransformer(Criteria.ALIAS_TO_ENTITY_MAP);
		Iterator it = getHibernateTemplate().findByCriteria(criteria,
				page.getFirstResult(), page.getPageSize()).iterator();
		while (it.hasNext()) {
			Map map = (Map) it.next();
			plh.add(map.get(Criteria.ROOT_ALIAS));
		}
		return plh;
	}

	/**
	 * 根据criteria进行分页查询。
	 * 
	 * @param criteria
	 *            查询条件
	 * @param page
	 *            分页信息
	 * @return 对象为根对象。
	 */
	@Override
	public List findByCriteria(DetachedCriteria criteria, Page page) {
		return findByCriteria(criteria, page, null);
	}

	/**
	 * 无分页查询
	 * 
	 * @param criteria
	 * @return 根对象的列表。
	 */
	@Override
	public List findByCriteria(DetachedCriteria criteria) {
		List results = new ArrayList();
		criteria.setResultTransformer(Criteria.ALIAS_TO_ENTITY_MAP);
		Iterator it = getHibernateTemplate().findByCriteria(criteria)
				.iterator();
		while (it.hasNext()) {
			Map map = (Map) it.next();
			results.add(map.get(Criteria.ROOT_ALIAS));
		}
		return results;
	}

	/**
	 * 按属性查找唯一对象.
	 */
	@Override
	public T findUniqueByProperty(Class<T> c, String propertyName, Object value) {
		return (T) createCriteria(c, Restrictions.eq(propertyName, value))
				.uniqueResult();
	}

	/**
	 * 根据Criterion条件创建Criteria,后续可进行更多处理,辅助函数.
	 */
	@Override
	public Criteria createCriteria(Class<T> c, Criterion... criterions) {
		Criteria criteria = getSession().createCriteria(c);
		for (Criterion cri : criterions) {
			criteria.add(cri);
		}
		return criteria;
	}

	/**
	 * 原生sql查询
	 */
	@Override
	public List createSQLQuery(String nativeSql) {
		Query query = getSession().createSQLQuery(nativeSql);
		return query.list();
	}

	/**
	 * 根据criteria和orderList进行分页查询。
	 * 
	 * 出于性能考虑排序信息请勿放在criteria里，由本方法负责。
	 * 
	 * @param criteria
	 *            查询条件
	 * @param page
	 *            分页信息
	 * @param orderList
	 *            定制化的排序列表
	 * @return JQGridListImpl,包含分页信息的对象列表。对象为根对象。
	 */
	public List findByCriteriaForJQGrid(DetachedCriteria criteria, Page page,
			List<Order> orderList) {
		if (page == null)
			throw new IllegalArgumentException(
					"page object can not be null value!");
		JQGridListImpl jqgl = new JQGridListImpl();
		jqgl.setPage(page.getRequestPage());
		jqgl.setObjectsPerPage(page.getPageSize());

		// get total record number
		criteria.setProjection(Projections.rowCount());
		List count = getHibernateTemplate().findByCriteria(criteria);
		int totalCount = ((Long) count.get(0)).intValue();
		jqgl.setRecords(totalCount);
		criteria.setProjection(null);

		// default order criteria
		if (page.getSortColumn() != null && page.getSortDirection() != null
				&& !"".equals(page.getSortColumn())
				&& !"".equals(page.getSortDirection())) {
			if (page.getSortDirection().equalsIgnoreCase(
					Page.SORT_DIRECTION_ASCENDING)) {
				criteria.addOrder(Order.asc(page.getSortColumn()));
			} else {
				criteria.addOrder(Order.desc(page.getSortColumn()));
			}
		}

		// custom order
		if (orderList != null) {
			for (Iterator<Order> it = orderList.iterator(); it.hasNext();) {
				criteria.addOrder(it.next());
			}
		}

		criteria.setResultTransformer(Criteria.ALIAS_TO_ENTITY_MAP);
		Iterator it = getHibernateTemplate().findByCriteria(criteria,
				page.getFirstResult(), page.getPageSize()).iterator();
		while (it.hasNext()) {
			Map map = (Map) it.next();
			jqgl.add(map.get(Criteria.ROOT_ALIAS));
		}
		return jqgl;
	}
	/**
	 * 根据criteria进行分页查询。
	 * 
	 * @param criteria
	 *            查询条件
	 * @param page
	 *            分页信息
	 * @return 对象为根对象。
	 */
	public List findByCriteriaForJQGrid(DetachedCriteria criteria, Page page) {
		return findByCriteriaForJQGrid(criteria, page, null);
	}

}